package org.xhy.quickstarter.generator.util;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.BeetlTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import org.xhy.quickstarter.generator.config.Config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 生成代码
 * @Author: Xhy
 * @gitee: https://gitee.com/XhyQAQ
 * @copyright: B站: https://space.bilibili.com/152686439
 * @CreateTime: 2023-06-04 11:51
 */
public class GeneratorUtils {
    /**
     *数据连接信息
     * @return DataSourceConfig
     */
    private static DataSourceConfig dataSourceConfig() {
        return new DataSourceConfig()
                .setDbType(Config.DB_TYPE)
                .setUrl(Config.DB_URL)
                .setUsername(Config.USERNAME)
                .setPassword(Config.PASSWORD)
                .setDriverName(Config.DRIVER)
                ;
    }


    private static GlobalConfig globalConfig() {
        return new GlobalConfig()
                .setAuthor(Config.AUTHOR)
                .setFileOverride(true) // 是否覆盖已有文件
                .setOpen(false) // 是否打开输出目录,不要开启,因是自定义生成了，这个不起效了
                .setDateType(DateType.TIME_PACK) // 时间采用java 8，（操作工具类：JavaLib => DateTimeUtils）
                // 自定义文件命名，注意 %s 会自动填充表实体属性！
                .setEntityName(Config.FILE_NAME_MODEL)
                .setMapperName(Config.FILE_NAME_DAO)
                .setXmlName(Config.FILE_NAME_XML)
                .setServiceName(Config.FILE_NAME_SERVICE)
                .setServiceImplName(Config.FILE_NAME_SERVICE_IMPL)
                .setControllerName(Config.FILE_NAME_CONTROLLER)
                .setIdType(IdType.UUID) // 主键类型 因现项目是UUID, 项目mpV3.2.0,代码生成器V3.4.0,但是MP必须高版本！
                .setSwagger2(Config.SWAGGER_SUPPORT)
                ;
    }


    private static StrategyConfig strategyConfig() {
        return new StrategyConfig()
                .setCapitalMode(true) // 全局大写命名 ORACLE 注意
                .setTablePrefix(Config.TABLE_PREFIXES)// 此处可以修改为您的表前缀(数组)
                .setFieldPrefix(Config.TABLE_PREFIXES) // 字段前缀
                .setNaming(NamingStrategy.underline_to_camel) // 表名生成策略
                .setInclude(Config.TABLE_NAMES)//修改替换成你需要的表名，多个表名传数组
                .setEntityLombokModel(true) // lombok实体
                .setLogicDeleteFieldName(Config.FIELD_LOGIC_DELETE_NAME) // 逻辑删除属性名称
                .setEntityTableFieldAnnotationEnable(true);
    }


    /**
     * 包信息配置
     * @return
     */
    private static PackageConfig packageConfig() {
        return new PackageConfig()
                .setParent(Config.PACKAGE_NAME)
                .setController(Config.PACKAGE_NAME_CONTROLLER)
                .setEntity(Config.PACKAGE_NAME_MODEL)
                .setMapper(Config.PACKAGE_NAME_DAO)
                .setXml(Config.PACKAGE_NAME_XML)
                .setService(Config.PACKAGE_NAME_SERVICE)
                .setServiceImpl(Config.PACKAGE_NAME_SERVICE_IMPL)
                ;
    }


    /**
     * 自定义模板输出位置
     * @return
     */
    private static InjectionConfig injectionConfig() {
        String[] commonField = Config.COMMON_FIELD;
        String packageName = Config.PACKAGE_NAME;

        InjectionConfig injectionConfig = new InjectionConfig() {
            @Override
            public void initMap() {
                Map<String, Object> map = new HashMap<>();
                map.put("commonField", commonField);
                this.setMap(map);
            }
        };
        List<FileOutConfig> fileOutConfigList = new ArrayList<FileOutConfig>();
        fileOutConfigList.add(new FileOutConfig("/templates/entity.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {

                return Config.OUTPUT_DIR + Config.DIR_PARTITION2 + getPath(packageName) + Config.DIR_NAME_ENTITY + tableInfo.getEntityName() + StringPool.DOT_JAVA;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/dto.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR + Config.DIR_PARTITION2 + getPath(packageName) + Config.DIR_NAME_DTO + tableInfo.getEntityName() + "DTO" + StringPool.DOT_JAVA;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/vo.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR + Config.DIR_PARTITION2 + getPath(packageName) + Config.DIR_NAME_VO + tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {

                return Config.OUTPUT_DIR + Config.DIR_PARTITION1+ getPath(packageName) + Config.DIR_NAME_XML + tableInfo.getXmlName() + StringPool.DOT_XML;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/mapper.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR + Config.DIR_PARTITION1 + getPath(packageName) + Config.DIR_NAME_MAPPER + tableInfo.getXmlName() + StringPool.DOT_JAVA;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/controller.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR  + Config.DIR_PARTITION1 + getPath(packageName) + Config.DIR_NAME_CONTROLLER + tableInfo.getControllerName() + StringPool.DOT_JAVA;
            }
        });

        fileOutConfigList.add(new FileOutConfig("/templates/service.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR + Config.DIR_PARTITION1 + getPath(packageName) + Config.DIR_NAME_SERVICE + tableInfo.getServiceName() + StringPool.DOT_JAVA;
            }
        });
        fileOutConfigList.add(new FileOutConfig("/templates/serviceImpl.java.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return Config.OUTPUT_DIR  + Config.DIR_PARTITION1 + getPath(packageName) + Config.DIR_NAME_IMPL + tableInfo.getServiceImplName() + StringPool.DOT_JAVA;
            }
        });
        injectionConfig.setFileOutConfigList(fileOutConfigList);
        return injectionConfig;
    }

    private static String getPath(String packageName){
        StringBuilder pathAll = new StringBuilder();
        for (String path : packageName.split("\\.")){
            pathAll.append(path).append("/");
        }
        return pathAll.toString();
    }

    /**
     * 获取模板引擎
     * @return 模板引擎 {@link AbstractTemplateEngine}
     */
    private static AbstractTemplateEngine getTemplateEngine() {
        String templateEngine = Config.TEMPLATE_ENGINE;
        switch (templateEngine) {
            case "velocity":
                return new VelocityTemplateEngine();
            case "freemarker":
                return new FreemarkerTemplateEngine();
            case "beetl":
                return new BeetlTemplateEngine();
        }
        return new VelocityTemplateEngine();
    }

    public static void execute() {
        GlobalConfig globalConfig = globalConfig();
        DataSourceConfig dataSourceConfig = dataSourceConfig();
        StrategyConfig strategyConfig = strategyConfig();
        PackageConfig packageConfig = packageConfig();
        InjectionConfig injectionConfig = injectionConfig();
        AbstractTemplateEngine templateEngine = getTemplateEngine();
        // 禁用默认的模板,不然会生成两份

        TemplateConfig templateConfig = new TemplateConfig().disable(TemplateType.values());
        new AutoGenerator()
                .setGlobalConfig(globalConfig)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                .setTemplateEngine(templateEngine)
                .setCfg(injectionConfig)
                .setTemplate(templateConfig)
                .execute();
    }

}
